package com.wmx.other;

import org.junit.Test;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.io.*;
import java.util.*;

/**
 * Java 对象深度克隆
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2020/7/31 16:39
 */
@SuppressWarnings("all")
public class DeepCopyTest {

    /**
     * Map 对象深度复制
     *
     * @param src 被克隆的对象，如：Map<String, Object>、Map<String, Person>等等
     * @param <K>
     * @param <V> :支持任意类型，如果是 java Bean，则必须实现 {@link Serializable} 接口实现序列化，否则报错
     * @return  ：失败时返回 null.
     */
    public static <K, V> Map<K, V> deepCopyMap(Map<K, V> src) {
        Assert.isTrue(!ObjectUtils.isEmpty(src), "参数不能为空");
        Map<K, V> dest = null;
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            out = new ObjectOutputStream(byteOut);
            out.writeObject(src);
            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            in = new ObjectInputStream(byteIn);
            dest = (Map<K, V>) in.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return dest;
    }

    /**
     * List 对象深度复制
     *
     * @param src ：被克隆的对象，如：List<String>、List<Map<String, Object>>、List<Person> 等等
     * @param <T> ：支持任意类型，如果是 java Bean，则必须实现 {@link Serializable} 接口实现序列化，否则报错
     * @return  ：失败时返回 null.
     */
    public static <T> List<T> deepCopyList(List<T> src) {
        Assert.isTrue(!ObjectUtils.isEmpty(src), "参数不能为空！");
        List<T> dest = null;
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            out = new ObjectOutputStream(byteOut);
            out.writeObject(src);
            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            in = new ObjectInputStream(byteIn);
            dest = (List<T>) in.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return dest;
    }

    /**
     * 对象深度克隆，使用泛型，支持任意对象。可以替代上面两个方法.
     *
     * @param src ：被克隆的对象，如 java bean，Set、List、Map 等等
     * @param <E> ：支持任意类型，如果是 java Bean，则必须实现 {@link Serializable} 接口实现序列化，否则报错
     * @return ：失败时返回 null.
     */
    public static <E> E deepCloneObject(E src) {
        Assert.isTrue(!ObjectUtils.isEmpty(src), "参数不能为空");
        E dest = null;
        ObjectOutputStream out = null;
        ObjectInputStream in = null;
        try {
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            out = new ObjectOutputStream(byteOut);
            out.writeObject(src);
            ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
            in = new ObjectInputStream(byteIn);
            dest = (E) in.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return dest;
    }

    @Test
    public void deepCopyMapTest1() throws IOException, ClassNotFoundException {
        Map<String, Object> map1 = new HashMap<>(2);
        map1.put("id", 3000);
        map1.put("name", "华安");

        Map<String, Object> deepCopy1 = deepCopyMap(map1);
        Map<String, Object> deepCopy2 = deepCloneObject(map1);

        deepCopy1.put("age", 45);
        deepCopy2.put("marry", false);

        //{name=华安, id=3000}
        System.out.println(map1);
        //{name=华安, id=3000, age=45}
        System.out.println(deepCopy1);
        //{name=华安, marry=false, id=3000}
        System.out.println(deepCopy2);
    }

    @Test
    public void deepCopyMapTest2() throws IOException, ClassNotFoundException {
        Person person = new Person(11, "无忌", new Date(), 7878.89F);
        Map<String, Person> map1 = new HashMap<>(2);
        map1.put("11", person);

        Map<String, Person> deepCopy = deepCopyMap(map1);
        Map<String, Person> cloneObject = deepCloneObject(map1);
        deepCopy.get("11").setName("悟空");
        cloneObject.get("11").setId(20002);

        //{11=Person{id=11, name='无忌', birthday=Tue Aug 11 14:57:06 CST 2020, salary=7878.89}}
        System.out.println(map1);
        //{11=Person{id=11, name='悟空', birthday=Tue Aug 11 14:57:06 CST 2020, salary=7878.89}}
        System.out.println(deepCopy);
        //{11=Person{id=20002, name='无忌', birthday=Tue Aug 11 14:57:06 CST 2020, salary=7878.89}}
        System.out.println(cloneObject);
    }

    @Test
    public void deepCopyMapTest3() {
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("id", "9527");
        dataMap.put("name", "华安");
        dataMap.put("list", list);

        Map<String, Object> cloneObject = deepCloneObject(dataMap);
        cloneObject.put("age", 33);
        List<Object> cloneList = (List) cloneObject.get("list");
        cloneList.add("5555");

        System.out.println(dataMap);//{name=华安, id=9527, list=[1, 2, 3]}
        System.out.println(cloneObject);//{name=华安, id=9527, list=[1, 2, 3, 5555], age=33}
    }

    @Test
    public void deepCopyListTest1() throws IOException, ClassNotFoundException {
        List<String> list = new ArrayList<>(Arrays.asList("中", "会话", "品牌"));
        List<String> copyList = deepCopyList(list);
        List<String> cloneObject = deepCloneObject(list);

        copyList.add("环境");
        cloneObject.add("回家");

        //[中, 会话, 品牌]
        System.out.println(list);
        //[中, 会话, 品牌, 环境]
        System.out.println(copyList);
        //[中, 会话, 品牌, 回家]
        System.out.println(cloneObject);
    }

    @Test
    public void deepCopyListTest2() throws IOException, ClassNotFoundException {
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> map1 = new HashMap<>(2);
        map1.put("id", 3000);
        map1.put("name", "华安");
        mapList.add(map1);

        List<Map<String, Object>> cloneList = deepCopyList(mapList);
        List<Map<String, Object>> cloneObject = deepCloneObject(mapList);

        cloneList.get(0).put("id", "2000");
        cloneObject.get(0).put("name", "悟空");

        //[{name=华安, id=3000}]
        System.out.println(mapList);
        //[{name=华安, id=2000}]
        System.out.println(cloneList);
        //[{name=悟空, id=3000}]
        System.out.println(cloneObject);
    }

    @Test
    public void deepCopyListTest3() throws IOException, ClassNotFoundException {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person(11, "无忌", new Date(), 7878.89F));

        List<Person> copyList = deepCopyList(personList);
        List<Person> cloneObject = deepCloneObject(personList);

        copyList.get(0).setName("后裔");
        cloneObject.get(0).setSalary(556576.67F);

        //[Person{id=11, name='无忌', birthday=Tue Aug 11 14:59:32 CST 2020, salary=7878.89}]
        System.out.println(personList);
        //[Person{id=11, name='后裔', birthday=Tue Aug 11 14:59:32 CST 2020, salary=7878.89}]
        System.out.println(copyList);
        //[Person{id=11, name='无忌', birthday=Tue Aug 11 14:59:32 CST 2020, salary=556576.7}]
        System.out.println(cloneObject);
    }

}
